#include "../server.hpp"
#include <fstream>

class Util
{
    public:
        // 字符串分割，将src字符串按照seq字符进行分割，得到的子串放入arry中，最终返回子串的数量
        static size_t Split(const std::string &src, const std::string &seq, std::vector<std::string> *arry)
        {
            int offset = 0;
            while(offset < src.size())
            {
                size_t pos = src.find(seq, offset);
                if(pos == std::string::npos)
                {
                    arry->push_back(src.substr(offset));
                    return arry->size();
                }
                if(pos != offset)
                    arry->push_back(src.substr(offset, pos - offset));
                offset = pos + seq.size();
            }
            return arry->size();
        }
        // 读取文件所有内容
        static bool ReadFile(const std::string &filename, std::string *buf)
        {
            std::ifstream ifs(filename, std::ios::binary);
            if(ifs.is_open() == false)
            {
                ERR_LOG("Open File:%s Failed!!", filename.c_str());
                return false;
            }
            size_t fsize = 0;
            ifs.seekg(0, ifs.end);  // 跳转到读写位置的文件末尾
            fsize = ifs.tellg();    // 获取相较于起始的偏移量，刚好就是文件大小
            ifs.seekg(0, ifs.beg);

            buf->resize(fsize);
            ifs.read(&(*buf)[0], fsize);
            if(ifs.good() == false)
            {
                ERR_LOG("Read File:%s Failed!!", filename.c_str());
                ifs.close();
                return false;
            }
            ifs.close();
            return true;
        }
        // 向文件写入数据
        static bool WriteFile(const std::string &filename, const std::string &buf)
        {
            // trunc选项代表不需要文件原有内容
            std::oftream ofs(filename, std::ios::binary | std::trunc);
            if(ofs.is_open() == false)
            {
                ERR_LOG("Open File:%s Failed!!", filename.c_str());
                return false;
            }           
            ofs.write(buf.c_str(), buf.size());
            if(ofs.good() == false)
            {
                ERR_LOG("Write File:%s Failed!!", filename.c_str());
                ofs.close();
                return false;
            }
            ofs.close();
            return true;
        }
        // URL编码，避免URL中资源路径与查询字符串中的特殊字符产生歧义
        // 编码格式：将特殊字符的ASCII码值，转换为两个16进制字符，前缀%  例：c++ -> c%2B%2B
        // 有绝对不编码的字符：. - _ ~ 以及字母和数字
        // W3C标准中规定param中的空格必须被编码为+，解码则是+转空格
        static std::string URLEncode(const std::string &url, bool convert_space_to_plus)
        {
            std::string res;
            for(auto &c : url)
            {
                if(c == ' ' && convert_space_to_plus)
                {
                    res += '+';
                    continue;
                }
                if(c == '.' || c == '-' || c == '_' || c == '~'|| isalnum(c))
                {
                    res += c;
                    continue;
                }
                char tmp[4] = {0};
                snprintf(tmp, 4, "%%%02X", c);
                res += tmp;
            }
            return res;
        }
        static char HexToI(char c)
        {
            if(c >= '0' && c <= '9')
            {
                return (c - '0');
            }
            else if(c >= 'a' && c <= 'z')
            {
                return (c - 'a' + 10);
            }
            else if(c >= 'A' && c <= 'Z')
            {
                return (c - 'A' + 10);
            }
            else
            {
                return -1;
            }
        }
        // URL解码
        static std::string URLDecode(const std::string &url, bool convert_plus_to_space)
        {
            std::string res;
            for(int i = 0; i < url.size(); i++)
            {
                if(url[i] == '%')
                {
                    char v1 = HexToI(url[i + 1]);
                    char v2 = HexToI(url[i + 2]);
                    char v = (v1 << 4) + v2;
                    res += v;
                    i += 2;
                    continue;
                }
                if(url[i] == '+' && convert_plus_to_space)
                {
                    res += ' ';
                    continue;
                }
                res += url[i];
            }
            return res;
        }
        // 通过状态码返回描述信息
        static std::string StatusDescribe();
        // 根据文件后缀迷宫获取mime
        static std::string ExtMime();
        // 判断文件是否为目录
        static bool IsDirectory();
        // 判断文件是否为普通文件
        static bool IsRegular();
        // 资源路径有效性判断
        static bool ValidPath();
};
